﻿using PBO.Data;
using PBO.Game.BattleLog;
using PBO.Network;
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using PBO.Network.Enumerations;

namespace PBO.Game.BattleClass
{
    public class BattleGround
    {
        public static readonly BattleTerrain[] TERRAINS = { BattleTerrain.Cave, BattleTerrain.Flat, BattleTerrain.Grass, BattleTerrain.Mountain, BattleTerrain.Sand, BattleTerrain.SnowField, BattleTerrain.Stadium, BattleTerrain.Water };

        #region event

        public event EventHandler WeatherChanged;

        protected void OnWeatherChanged()
        {
            if (WeatherChanged != null)
            {
                this.WeatherChanged(this, EventArgs.Empty);
            }
        }

        #endregion

        private bool _magicRoom;
        private int magicRoomCounter;

        private bool _miracleRoom;
        private int miracleRoomCounter;

        private bool _gravity;
        private int gravityCounter;

        public bool waterSport;
        public bool mudSport;

        public Pokemon followPokemon;
        private Battle battle;

        public BattleGround(BattleTerrain terrain, Battle battle)
        {
            this.Terrain = terrain;
            this.battle = battle;
        }

        public BattleTerrain Terrain { get; private set; }
        public int WeatherCount { get; private set; }

        private Weather _weather;
        public Weather Weather
        {
            get
            {
                return this.AirLock ? Weather.Normal : _weather;
            }
        }

        public bool NewWeather(Weather weatherValue, Pokemon maker, ILogBuilder log, bool traitEff = false)
        {
            if (this.Weather == weatherValue)
            {
                if (traitEff) WeatherCount = -1;
                return false;
            }
            else
            {
                WeatherCount = 5;
                _weather = weatherValue;
                switch (_weather)
                {
                    case Weather.Rainy:
                        log.AppendMsg("EnHeavyRain");
                        //log.AddText("场上下起雨了！");
                        if (maker.GetItem() == Item.DampRock)
                            WeatherCount = 8;
                        break;
                    case Weather.Sunny:
                        log.AppendMsg("EnIntenseSunlight");
                        //log.AddText("太阳出来了！");
                        if (maker.GetItem() == Item.HeatRock)
                            WeatherCount = 8;
                        break;
                    case Weather.SandStorm:
                        log.AppendMsg("EnSandstorm");
                        //log.AddText("场上刮起了沙尘暴！");
                        if (maker.GetItem() == Item.SmoothRock)
                            WeatherCount = 8;
                        break;
                    case Weather.HailStorm:
                        log.AppendMsg("EnHailstorm");
                        //log.AddText("场上下起了冰雹！");
                        if (maker.GetItem() == Item.IcyRock)
                            WeatherCount = 8;
                        break;
                }
                if (traitEff)
                    WeatherCount = -1;
                if (!AirLock)
                    ChangeWeather();
                return true;
            }
        }

        public bool TrickRoom { get; private set; }
        private int trickRoomCounter;
        public void TrickRoomChange(ILogBuilder log)
        {
            this.TrickRoom = !this.TrickRoom;
            if (this.TrickRoom == true)
            {
                trickRoomCounter = 5;
                log.AppendMsg("EnTrickRoom");
                //log.AddText("5回合内速度慢的先手！");
            }
        }

        public bool MagicRoom
        {
            get { return _magicRoom; }
        }

        public void MagicRoomChange(ILogBuilder log)
        {
            if (!_magicRoom)
            {
                _magicRoom = true;
                magicRoomCounter = 5;
                log.AppendMsg("EnMagicRoom");
                //log.AppendText("5回合内道具失效！");
            }
        }

        public bool MiracleRoom
        {
            get { return _miracleRoom; }
        }

        public void MiracleRoomChange(ILogBuilder log)
        {
            if (!_miracleRoom)
            {
                _miracleRoom = true;
                miracleRoomCounter = 5;
                log.AppendMsg("EnWonderRoom");
                //log.AppendText("5回合内物防与特防交换！");
            }
            else
            {
                _miracleRoom = false;
            }
        }

        public bool Gravity
        {
            get { return _gravity; }
        }

        public void Gravitate(ILogBuilder log)
        {
            _gravity = true;
            gravityCounter = 5;
            log.AppendMsg("EnGravity");
            //log.AddText("全场都受到了重力的作用！");

            foreach (Pokemon pm in battle.SelectedPokemons)
            {
                GravitatePM(log, pm);
            }
        }

        private void GravitatePM(ILogBuilder log, Pokemon pm)
        {
            if (pm.BattleState.fly || pm.BattleState.jump)
            {
                pm.BattleState.jump = false;
                pm.BattleState.fly = false;
                log.AppendMsg("Gravity", pm.CustomName);
                //log.AddText(pm.MyTeam.GetPlayerName(pm) + "的" + pm.CustomName + "回到了地面！");
            }
        }

        public bool AirLock
        {
            get
            {
                return battle.SelectedPokemons.Any(p => p.HealthPower > 0 && (p.GetSelTrait() == Trait.CloudNine || p.GetSelTrait() == Trait.AirLock));
            }
        }

        public bool Unaware
        {
            get
            {
                return battle.SelectedPokemons.Any(p => p.HealthPower > 0 && p.GetSelTrait() == Trait.Unaware);
            }
        }

        public bool Uproar
        {
            get
            {
                return battle.SelectedPokemons.Any(p => p.HealthPower > 0 && p.BattleState.Uproar);
            }
        }

        public bool Damp
        {
            get
            {
                return battle.SelectedPokemons.Any(p => p.HealthPower > 0 && p.GetSelTrait() == Trait.Damp);
            }
        }

        public void CountOfTurnEnd(ILogBuilder log)
        {
            if (TrickRoom)
            {
                trickRoomCounter--;
                if (trickRoomCounter == 0)
                {
                    TrickRoom = false;
                    log.AppendMsg("DeTrickRoom");
                    //log.AddText("欺骗空间消失了！");
                }
            }
            if (Gravity)
            {
                gravityCounter -= 1;
                if (gravityCounter == 0)
                {
                    _gravity = false;
                    log.AppendMsg("DeGravity");
                    //log.AddText("重力的作用消失了！");
                }
            }
            if (MagicRoom)
            {
                magicRoomCounter -= 1;
                if (magicRoomCounter == 0)
                {
                    _magicRoom = false;
                }
            }
            if (MiracleRoom)
            {
                miracleRoomCounter -= 1;
                if (miracleRoomCounter == 0)
                {
                    _miracleRoom = false;
                }
            }
            if (!Echo)
            {
                EchoCounter = 0;
            }
            else
            {
                Echo = false;
                EchoCounter++;
            }
            SingARound = false;
            CountWeather(log);
        }

        private void CountWeather(ILogBuilder log)
        {
            if (_weather != Weather.Normal)
            {
                WeatherCount--;
                if (WeatherCount != 0)
                {
                    switch (Weather)
                    {
                        case Weather.HailStorm:
                            log.AppendMsg("Hailstorm");
                            //log.AddText("冰雹继续下着");
                            WeatherHurt(battle.SelectedPokemons, log);
                            break;
                        case Weather.Rainy:
                            log.AppendMsg("Raining");
                            //log.AppendText("雨一直下");
                            break;
                        case Weather.SandStorm:
                            log.AppendMsg("Sandstorm");
                            //log.AddText("沙尘暴继续刮着");
                            WeatherHurt(battle.SelectedPokemons, log);
                            break;
                        case Weather.Sunny:
                            log.AppendMsg("Sunny");
                            //log.AppendText("天气十分晴朗");
                            break;
                    }
                }
                else
                {
                    WeatherStopLog(_weather, log);
                    _weather = Weather.Normal;
                    //log.AppendText("天气恢复了正常");
                    ChangeWeather();
                }
            }
        }

        private static void WeatherStopLog(Weather weather, ILogBuilder log)
        {
            switch (weather)
            {
                case Weather.Sunny:
                    log.AppendMsg("DeIntenseSunlight");
                    break;
                case Weather.Rainy:
                    log.AppendMsg("DeHeavyRain");
                    break;
                case Weather.SandStorm:
                    log.AppendMsg("DeSandstorm");
                    break;
                case Weather.HailStorm:
                    log.AppendMsg("DeHailstorm");
                    break;
            }
        }

        private void WeatherHurt(IEnumerable<Pokemon> team, ILogBuilder log)
        {
            foreach (Pokemon pm in team)
            {
                WeatherHurt(pm, log);
            }
        }

        private void WeatherHurt(Pokemon pm, ILogBuilder log)
        {
            if (pm.GetSelTrait() != Trait.MagicGuard && !(pm.HealthPower == 0 || pm.BattleState.dig || pm.BattleState.dive))
            {
                switch (Weather)
                {
                    case Weather.SandStorm:
                        if (!(pm.HaveType(BattleType.Ground) || pm.HaveType(BattleType.Rock) || pm.HaveType(BattleType.Steel) || pm.GetSelTrait() == Trait.SandVeil))
                        {
                            log.AppendMsg("SandstormHurt", pm.CustomName);
                            //log.AddText(_with2.MyTeam.GetPlayerName(pm) + "的" + _with2.CustomName + "受到了沙尘暴的伤害！");
                            pm.HurtFraction(16);
                        }
                        break;
                    case Weather.HailStorm:
                        if (!(pm.HaveType(BattleType.Ice) || pm.GetSelTrait() == Trait.SnowCloak))
                        {
                            log.AppendMsg("HailstormHurt", pm.CustomName);
                            //log.AddText(_with2.MyTeam.GetPlayerName(pm) + "的" + _with2.CustomName + "受到了冰雹的伤害！");
                            pm.HurtFraction(16);
                        }
                        break;
                }
            }
        }

        #region ChangeWeather

        private void ChangeWeather()
        {
            foreach (var pm in battle.SelectedPokemons)
            {
                ChangeWeather(pm);
            }
        }

        public void ChangeWeather(Pokemon pm)
        {
            ChangeForecast(pm, this.Weather);

            var move = pm.GetSelMoves().FirstOrDefault(m => m.Data.AddEffect2 == MoveAdditionalEffect.天气球);
            if (move != null)
            {
                move.SetType(GetWeatherBallType(this.Weather));
            }
        }

        private static BattleType GetWeatherBallType(Weather weather)
        {
            switch (weather)
            {
                case Weather.Normal:
                    return BattleType.Normal;
                case Weather.HailStorm:
                    return BattleType.Ice;
                case Weather.Sunny:
                    return BattleType.Fire;
                case Weather.SandStorm:
                    return BattleType.Rock;
                case Weather.Rainy:
                    return BattleType.Water;
                default:
                    return BattleType.Normal;
            }
        }

        private static void ChangeForecast(Pokemon pm, Weather weather)
        {
            var ability = pm.GetSelTrait();
            if (ability != Trait.Forecast) return;

            pm.Type2 = BattleType.None;
            switch (weather)
            {
                case Weather.Normal:
                case Weather.SandStorm:
                    pm.BattleState.traitRaised = false;
                    pm.Type1 = BattleType.Normal;
                    pm.FrontImage = null;
                    pm.BackImage = null;
                    break;
                case Weather.HailStorm:
                    pm.BattleState.traitRaised = true;
                    pm.Type1 = BattleType.Ice;
                    pm.FrontImage = Properties.Resources.Hailstrom;
                    pm.BackImage = Properties.Resources.HailstromBack;
                    break;
                case Weather.Sunny:
                    pm.BattleState.traitRaised = true;
                    pm.Type1 = BattleType.Fire;
                    pm.FrontImage = Properties.Resources.Sunny;
                    pm.BackImage = Properties.Resources.SunnyBack;
                    break;
                case Weather.Rainy:
                    pm.BattleState.traitRaised = true;
                    pm.Type1 = BattleType.Water;
                    pm.FrontImage = Properties.Resources.Rainy;
                    pm.BackImage = Properties.Resources.RainyBack;
                    break;
            }
        }

        #endregion

        public bool Echo { get; private set; }
        public int EchoCounter { get; private set; }
        public bool SingARound { get; private set; }
    }
}
